﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using hlavny.modul2;

namespace hlavny.modul4
{
    class Blok
    {
        #region privatne atributy
        private CSysTables sysTables;
        private CSysColumns sysColumns;
        private int tabulkaId;
        private int velkostJednehoZaznamu;
        private readonly static int velkostBlokuZaznamov = 4;
        private int velkostBlokuBajtov;
        /// <summary>
        /// pocet aktualne obsadenych zaznamov v bloku / inak povedane nasledujuci volny
        /// </summary>
        private int nasledujuciVolny = 0;
        private Zaznam[] data = new Zaznam[velkostBlokuZaznamov];
        private bool[] obsadene = new bool[velkostBlokuZaznamov];
        private Zaznam vzorovyZaznam;
        #endregion





        #region properties
        public int VelkostBlokuZaznamov
        {
            get { return velkostBlokuZaznamov; }
        }


        public int NasledujuciVolny
        {
            get { return nasledujuciVolny; }
            set { nasledujuciVolny = value; }
        }


        public int VelkostJednehoZaznamu
        {
            get { return velkostJednehoZaznamu; }
            set { velkostJednehoZaznamu = value; }
        }


        public int VelkostBlokuBajtov
        {
            get { return velkostBlokuBajtov; }
            set { velkostBlokuBajtov = value; }
        }

        internal Zaznam VzorovyZaznam
        {
            get { return vzorovyZaznam; }
            set { vzorovyZaznam = value; }
        }
        #endregion





        #region metody
        public byte[] ToByte()
        {
            byte[] buffer = new byte[velkostBlokuBajtov];
            for (int i = 0; i < velkostBlokuZaznamov; i++)
            {
                if (obsadene[i] == true)
                {
                    buffer[i] = 1;
                    byte[] pom = data[i].ToByte();
                    Array.Copy(pom, 0, buffer, velkostBlokuZaznamov + i * velkostJednehoZaznamu, pom.Length);
                }
                else
                {
                    buffer[i] = 0;
                }
            }
            return buffer;
        }


        public void FromByte(byte[] paBuffer)
        {
            nasledujuciVolny = 0;
            byte[] novyZaznamBuffer = new byte[velkostJednehoZaznamu];
            for (int i = 0; i < velkostBlokuZaznamov; i++)
            {
                if (paBuffer[i] == 1)
                {
                    Array.Copy(paBuffer, velkostBlokuZaznamov + i * velkostJednehoZaznamu, novyZaznamBuffer, 0, novyZaznamBuffer.Length);
                    data[i] = this.VytvorZaznam(novyZaznamBuffer);
                    obsadene[i] = true;
                    nasledujuciVolny = i + 1;
                }
                else if (paBuffer[i] == 0)
                {
                    data[i] = this.VytvorZaznam();
                    obsadene[i] = false;
                }
                else
                {
                    throw new Exception("Zly bajt");
                }
            }
        }


        public Blok(CSysTables paSysTables, CSysColumns paSysColumns, int paTabulkaId, byte[] paBuffer)
        {
            this.init(paSysTables, paSysColumns, paTabulkaId);
            this.FromByte(paBuffer);
        }


        public Blok(CSysTables paSysTables, CSysColumns paSysColumns, int paTabulkaId)
        {
            init(paSysTables, paSysColumns, paTabulkaId);
        }


        private void init(CSysTables paSysTables, CSysColumns paSysColumns, int paTabulkaId)
        {
            sysTables = paSysTables;
            sysColumns = paSysColumns;
            tabulkaId = paTabulkaId;
            vzorovyZaznam = this.VytvorZaznam();
            velkostJednehoZaznamu = vzorovyZaznam.VelkostZaznamu;
            //prve bity su na ulozenie toho, ci su jednotlive miesta na zaznam obsadene
            velkostBlokuBajtov = velkostBlokuZaznamov + velkostJednehoZaznamu * velkostBlokuZaznamov;
            for (int i = 0; i < velkostBlokuZaznamov; i++)
            {
                data[i] = this.VytvorZaznam();
                obsadene[i] = false;
            }
        }


        public void Add(Zaznam paZaznam)
        {
            // pokial je miesto v bloku
            if (nasledujuciVolny < velkostBlokuZaznamov)
            {
                data[nasledujuciVolny] = paZaznam;
                obsadene[nasledujuciVolny] = true;
                nasledujuciVolny++;
            }
            else
            {
                throw new Exception("Blok je plny.");
            }
        }


        public void Remove(int paCisloVBloku)
        {
            if (obsadene[paCisloVBloku] == false)
            {
                throw new Exception("Already deleted.");
            }
            else
            {
                obsadene[paCisloVBloku] = false;
            }
        }


        public void Remove(Zaznam paZaznam)
        {
            bool vymazane = false;
            int i = 0;
            while (i < nasledujuciVolny && !vymazane)
            {
                if (data[i] == paZaznam)
                {
                    obsadene[i] = false;
                    vymazane = true;
                }
                i++;
            }
        }


        public Zaznam VytvorZaznam()
        {
            return new Zaznam(sysTables, sysColumns, tabulkaId);
        }


        public Zaznam VytvorZaznam(byte[] paBuffer)
        {
            return new Zaznam(sysTables, sysColumns, tabulkaId, paBuffer);
        }


        /// <summary>
        /// vrati pocet zaznamov, ktore sa daju vlozit do bloku
        /// </summary>
        public int Free()
        {
            return velkostBlokuZaznamov - nasledujuciVolny;
        }


        /// <summary>
        /// vrati pocet pouzitych pozicii (aj plne aj zmazane)
        /// </summary>
        public int DajPocetPouzitychPozicii()
        {
            return nasledujuciVolny;
        }


        /// <summary>
        /// vrati pocet neprazdnych (platnych) zaznamov
        /// </summary>
        /// <returns></returns>
        public int DajPocetNeprazdnych()
        {
            int vystup = 0;
            for (int i = 0; i < velkostBlokuZaznamov; i++)
            {
                if (obsadene[i] == true)
                {
                    vystup++;
                }
            }
            return vystup;
        }

        /// <summary>
        /// vrati najblizsi neprazdny zaznam z bloku, inak null
        /// </summary>
        /// <param name="paPoradieZaznamuVBloku"></param>
        /// <returns></returns>
        public Zaznam DajDalsiZaznamZBloku(int paPoradieZaznamuVBloku, out int poradieZaznamu)
        {
            for (int i = paPoradieZaznamuVBloku; i < velkostBlokuZaznamov; i++)
            {
                if (obsadene[i] == true)
                {
                    poradieZaznamu = i;
                    return data[i];
                }
            }
            poradieZaznamu = -1;
            return null;
        }
        #endregion
    }
}
